import java.sql.Date;
import java.sql.Time;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Scanner;

public class MessageEditor {
	
	/**
	 * This is the message header.
	 */
	private static final String HEADER = "MESSAGEHEADER";
	
	/**
	 * This is the message stop.
	 */
	private static final String STOP = "MESSAGESTOP";
	
	/**
	 * This is the break sign.
	 */
	public static final String breakSign = ":";
	
	/**
	 * This is the separator.
	 */
	private static final String dBreak = " <>" + breakSign + "<> ";
	
	/**
	 * Makes a message from a List of message segments
	 * @param list
	 * @return
	 */
	public static String makeMessage(List<String> list){
		String message = "";
		if(list.size() > 1){
			message += list.get(0);
			for(int i = 1; i < list.size(); i++){
				message += dBreak + list.get(i);
			}
			return HEADER + dBreak + message + dBreak + STOP;
		}else{
			return null;
		}
	}
	
	/**
	 * This method parses a message into seperate parts.
	 * 
	 * @param message the message that needs to be parsed.
	 * 
	 * @return a List of all the individual String segments of the message.
	 */
	public static List<String> parseMessage(String message){
		List<String> list = new ArrayList<String>();
		Scanner scan = new Scanner(message);
		String next = getNextSegment(scan);
		
		while(next != null){
			list.add(next);
			next = getNextSegment(scan);
		}
		
		if(list.get(0).equals(HEADER + " ")){
			list.remove(0);
		}
		
		if(list.get(list.size() - 1).equals(STOP + " ")){
			list.remove(list.size() - 1);
		}
		
		return list;
	}
	
	/**
	 * This class gets the next message section out of a scanner that holds a message.
	 * 
	 * @param scanner the Scanner that holds the message.
	 * 
	 * @return the next portion of the message.
	 */
	private static String getNextSegment(Scanner scanner){
		String next, segment;
		segment = "";
		
		try{
			next = scanner.next();
			while(!next.equals(breakSign)){
				segment += next + " ";
				next = scanner.next();
			}
			return segment;
		}catch(NoSuchElementException e){
			if(segment.equals("")){
				return null;
			}
			return segment;
		}catch(IllegalStateException e){
			System.err.println("ILLEGAL STATE EXCEPTION: getNextSegment().");
			return null;
		}
	}
	
	/**
	 * Makes a LOGIN message
	 * 
	 * @param username the user name that the user entered.
	 * @param password the password that the user entered.
	 * @param role the role that the user selected.
	 * 
	 * @return a LOGIN message.
	 */
	public static String makeLogin(String username, String password, int role){
		String login = "LOGIN" + dBreak
					   + username + dBreak
					   + password + dBreak
					   + role;
		return HEADER + dBreak + login + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param user the User that will be added to the database.
	 * 
	 * @return
	 */
	public static String makeAddUser(User user){
		String addUser = "ADDUSER" + dBreak
					   + UserMessageEditor.getMessage(user);
		return HEADER + dBreak + addUser + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param ssn the SSN of the user to be looked up.
	 * 
	 * @return
	 */
	public static String makeLoadUser(int ssn){
		String loadUser = "LOADUSER" + dBreak
						  + ssn;
		return HEADER + dBreak + loadUser + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param ssn the ssn of the user to be updated.
	 * @param user the User data of the user to be updated.
	 * 
	 * @return
	 */
	public static String makeUpdateUser(int ssn, User user){
		String updateUser = "UPDATEUSER" + dBreak
							+ ssn + dBreak
							+ UserMessageEditor.getMessage(user);
		return HEADER + dBreak + updateUser + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param ssn the SSN of the user to be deleted.
	 * 
	 * @return
	 */
	public static String makeDeleteUser(int ssn){
		String deleteUser = "DELETEUSER" + dBreak
							+ ssn;
		return HEADER + dBreak + deleteUser + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param name the name of the user that you are searching for.
	 * 
	 * @return
	 */
	public static String makeSearchUser(String name){
		String searchUser = "SEARCHUSER" + dBreak
							+ name;
		return HEADER + dBreak + searchUser + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param app the Appointment that needs to be added to the database.
	 * 
	 * @return
	 */
	public static String makeAddApp(Appointment app){
		String addApp = "ADDAPP" + dBreak
						+ AppointmentMessageEditor.getMessage(app);
		return HEADER + dBreak + addApp + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param date the Date that the appointment takes place
	 * 
	 * @return
	 */
	public static String makeLoadApp(Date date){
		String loadApp = "LOADAPP" + dBreak
						 + date.toString();
		return HEADER + dBreak + loadApp + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param app the Appointment to be updated.
	 * 
	 * @return 
	 */
	public static String makeUpdateApp(Appointment app){
		String updateApp = "UPDATEAPPOINTMENT" + dBreak
						   + AppointmentMessageEditor.getMessage(app);
		return HEADER + dBreak + updateApp + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param ssn the SSN of the user who set up the appointment.
	 * @param date the date that the appointment takes place.
	 * 
	 * @return
	 */
	public static String makeDeleteApp(int ssn, Date date){
		String deleteApp = "DELETEAPP" + dBreak
		 				 + ssn + dBreak
		 				 + date.toString();
		return HEADER + dBreak + deleteApp + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param date the date that you want to find appointments for.
	 * 
	 * @return
	 */
	public static String makeSearchAppDate(Date date){
		String searchAppDate = "SEARCHAPPDATE" + dBreak
							   + date.toString();
		return HEADER + dBreak + searchAppDate + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param ssn the SSN of the user that you want to look up appointments for.
	 * 
	 * @return
	 */
	public static String makeSearchAppSSN(int ssn){
		String searchAppSSN = "SEARCHAPPSSN" + dBreak
							  + ssn;
		return HEADER + dBreak + searchAppSSN + dBreak + STOP;
	}
	
	/**
	 * Makes a QUIT message.
	 * 
	 * @return a QUIT message.
	 */
	public static String makeQuit(){
		String quit = "QUIT";
		return HEADER + dBreak + quit + dBreak + STOP;
	}
	
	/**
	 * 
	 * 
	 * @param b the boolean that shows if the authentication of the username, password, and role worked.
	 * @param role the int that determines which role the user can log in as.
	 * 
	 * @return
	 */
	public static String makeRLogin(User user){
		String rLogin = "rLOGIN" + dBreak
						+ UserMessageEditor.getMessage(user);
		return HEADER + dBreak + rLogin + dBreak + STOP;
	}
	
	/**
	 * retrieves a User from an rLOGIN message.
	 * 
	 * @param message the String that holds the rLOGIN message
	 * 
	 * @return the User that was returned upon a successful login
	 */
	public static User parseRLogin(String message){
		List<String> msg = parseMessage(message);
		if(msg.get(0).equals("rLOGIN ")){
			return UserMessageEditor.getUser(msg.get(1));
		}
		return null;
	}
	
	/**
	 * 
	 * 
	 * @param user the User data that is being retrieved from the database.
	 * 
	 * @return
	 */
	public static String makeRLoadUser(User user){
		String rLoadUser = "rLOADUSER" + dBreak
						   + UserMessageEditor.getMessage(user);
		return HEADER + dBreak + rLoadUser + dBreak + STOP;
	}
	
	/**
	 * retrieves a user from the rLOADUSER
	 * 
	 * @param message the String that holds the rLOADUSER message
	 * 
	 * @return the User that was sent back by the database.
	 */
	public static User parseRLoadUser(String message){
		List<String> msg = parseMessage(message);
		if(msg.get(0).equals("rLOADUSER ")){
			return UserMessageEditor.getUser(msg.get(1));
		}
		return null;
	}
	
	/**
	 * 
	 * 
	 * @param list the list of users that were found in the search.
	 * 
	 * @return
	 */
	public static String makeRSearchUser(List<User> list){
		String rSearchUser = "rSEARCHUSER";
		
		for(int i = 0; i < list.size(); i++){
			String user = UserMessageEditor.getMessage(list.get(i));
			if(user != null){
				rSearchUser += dBreak + user;
			}
		}
		
		return HEADER + dBreak + rSearchUser + dBreak + STOP;
	}
	
	public static List<User> parseRSearchUser(String message){
		List<String> msg = parseMessage(message);
		if(msg.get(0).equals("rSEARCHUSER ")){
			List<User> users = new ArrayList<User>();
			for(int i = 1; i < msg.size(); i++){
				users.add(UserMessageEditor.getUser(msg.get(i)));
			}
			return users;
		}
		return null;
	}
	
	/**
	 * 
	 * 
	 * @param list the list of Appointments found in the search by date.
	 * 
	 * @return
	 */
	public static String makeRSearchAppDate(List<Appointment> list){
		String rSearchAppDate = "rSEARCHAPPDATE";
		
		for(int i = 0; i < list.size(); i++){
			Appointment app = list.get(i);
			if(app != null){
				rSearchAppDate += dBreak + AppointmentMessageEditor.getMessage(app);
			}
		}
		
		return HEADER + dBreak + rSearchAppDate + dBreak + STOP;
	}
	
	public static List<Appointment> parseRSearchAppDate(String message){
		List<String> msg = parseMessage(message);
		if(msg.get(0).equals("rSEARCHAPPDATE ")){
			List<Appointment> apps = new ArrayList<Appointment>();
			for(int i = 1; i < msg.size(); i++){
				apps.add(AppointmentMessageEditor.getAppointment(msg.get(i)));
			}
			return apps;
		}
		return null;
	}
	
	/**
	 * 
	 * 
	 * @param list the list of Appointments found in the search by SSN.
	 * 
	 * @return
	 */
	public static String makeRSearchAppSSN(List<Appointment> list){
		String rSearchAppSSN = "rSEARCHAPPSSN";
		
		for(int i = 0; i < list.size(); i++){
			Appointment app = list.get(i);
			if(app != null){
				rSearchAppSSN += dBreak + AppointmentMessageEditor.getMessage(app);
			}
		}
		
		return HEADER + dBreak + rSearchAppSSN + dBreak + STOP;
	}
	
	public static List<Appointment> parseRSearchAppSSN(String message){
		List<String> msg = parseMessage(message);
		if(msg.get(0).equals("rSEARCHAPPSSN ")){
			List<Appointment> apps = new ArrayList<Appointment>();
			for(int i = 1; i < msg.size(); i++){
				apps.add(AppointmentMessageEditor.getAppointment(msg.get(i)));
			}
			return apps;
		}
		return null;
	}
	
	public static void main(String[] args){
		
		/* *************************************************************
		 * *************************************************************
		 * *************************************************************
		 * 
		 * This creates the first user.
		 */
		boolean[] roles = {true, false, true, false};
		
		User user = new User("bjones4", "password", roles, 2315, "Bob Jones");
		user.setAddress("167 Something Road, Atlanta GA 30456");
		user.setPhone("(555) 837 - 7256");
		user.setEmail("bjones4@soandso.org");
		user.setPharmacy("Typical Medicines Inc.");
		user.setInsurance("Loan Shark Insurance");
		user.setCellPhone("(555) 111 - 4783");
		user.setAllergies("Dogs, cats, goldfish, and dustmites");
		user.setGender(Gender.MALE);
		user.setBirthDate(new Date(78, 2, 18));
		
		TreatmentRecord tr = new TreatmentRecord();
		tr.setAttendingNurse("Silly Billy");
		tr.setBpDiastolic(4);
		tr.setBpSystolic(16);
		tr.setDate(new Date(12, 10, 12));
		tr.setDiagnosis("The patient is very, very sick.");
		tr.setFollowUpInstructions("Do stuff after this appointment.");
		tr.setOtherInstructions("Do other stuff too.");
		tr.setHeight(new Height(12, 12));
		tr.setLabWork("This lab work needs to get done.");
		tr.setPrescription("Take these pills.");
		tr.setPulse(17);
		tr.setSymptoms("This stuff is happening");
		tr.setTemperature(5.68);
		tr.setTime(new Time(3, 45, 32));
		tr.setTreatingDoctor("Dr. John Whatever");
		tr.setWeight(8.9);
		
		TreatmentRecord tr2 = new TreatmentRecord();
		tr2.setAttendingNurse("Sally Jones");
		tr2.setBpDiastolic(4);
		tr2.setBpSystolic(16);
		tr2.setDate(new Date(12, 10, 12));
		tr2.setDiagnosis("The patient is very, very sick.");
		tr2.setFollowUpInstructions("Do stuff after this appointment.");
		tr2.setOtherInstructions("Do other stuff too.");
		tr2.setHeight(new Height(12, 12));
		tr2.setLabWork("This lab work needs to get done.");
		tr2.setPrescription("Take these pills.");
		tr2.setPulse(17);
		tr2.setSymptoms("This stuff is happening");
		tr2.setTemperature(5.68);
		tr2.setTime(new Time(3, 45, 32));
		tr2.setTreatingDoctor("Dr. Jim Somebody");
		tr2.setWeight(8.9);
		
		user.addTreatmentRecord(tr);
		user.addTreatmentRecord(tr2);
		
		/* *************************************************************
		 * *************************************************************
		 * *************************************************************
		 * 
		 * This creates the second user
		 */
		
		User user2 = new User("fventura3", "strqdr", roles, 73859, "Fransisco Ventura");
		user2.setAddress("167 Something Road, Atlanta GA 30456");
		user2.setPhone("(555) 837 - 7256");
		user2.setEmail("bjones4@soandso.org");
		user2.setPharmacy("Typical Medicines Inc.");
		user2.setInsurance("Loan Shark Insurance");
		user2.setCellPhone("(555) 111 - 4783");
		user2.setAllergies("Dogs, cats, goldfish, and dustmites");
		user2.setGender(Gender.MALE);
		user2.setBirthDate(new Date(152, 8, 7));
		
		TreatmentRecord tr3 = new TreatmentRecord();
		tr3.setAttendingNurse("Silly Billy");
		tr3.setBpDiastolic(4);
		tr3.setBpSystolic(16);
		tr3.setDate(new Date(12, 10, 12));
		tr3.setDiagnosis("The patient is very, very sick.");
		tr3.setFollowUpInstructions("Do stuff after this appointment.");
		tr3.setOtherInstructions("Do other stuff too.");
		tr3.setHeight(new Height(12, 12));
		tr3.setLabWork("This lab work needs to get done.");
		tr3.setPrescription("Take these pills.");
		tr3.setPulse(17);
		tr3.setSymptoms("This stuff is happening");
		tr3.setTemperature(5.68);
		tr3.setTime(new Time(3, 45, 32));
		tr3.setTreatingDoctor("Dr. John Whatever");
		tr3.setWeight(8.9);
		

		TreatmentRecord tr4 = new TreatmentRecord();
		tr4.setAttendingNurse("Sally Jones");
		tr4.setBpDiastolic(4);
		tr4.setBpSystolic(16);
		tr4.setDate(new Date(12, 10, 12));
		tr4.setDiagnosis("The patient is very, very sick.");
		tr4.setFollowUpInstructions("Do stuff after this appointment.");
		tr4.setOtherInstructions("Do other stuff too.");
		tr4.setHeight(new Height(12, 12));
		tr4.setLabWork("This lab work needs to get done.");
		tr4.setPrescription("Take these pills.");
		tr4.setPulse(17);
		tr4.setSymptoms("This stuff is happening");
		tr4.setTemperature(5.68);
		tr4.setTime(new Time(3, 45, 32));
		tr4.setTreatingDoctor("Dr. Jim Somebody");
		tr4.setWeight(8.9);
		
		user2.addTreatmentRecord(tr);
		user2.addTreatmentRecord(tr4);
		
		/* *********************************************************
		 * *********************************************************
		 * *********************************************************
		 * 
		 * Here is the first Appointment
		 */
		Date date = new Date(111, 4, 12);
		Time ts = new Time(3, 12, 35);
		Time te = new Time(3, 38, 12);
		Appointment app = new Appointment(678, date, ts, te, "Doc John", "Susie");
		app.setReason("My tooth hurts!!!!!");
		
		/* *********************************************************
		 * *********************************************************
		 * *********************************************************
		 * 
		 * Here is the second appointment
		 */
		Date date2 = new Date(115, 3, 4);
		Time ts2 = new Time(4, 51, 34);
		Time te2 = new Time(7, 21, 00);
		Appointment app2 = new Appointment(678, date2, ts2, te2, "Doc John", "Susie");
		app2.setReason("My back hurts!!!!!");
		
		
		
		/* ////////////////////////////////////////////////
		 * ************************************************
		 * 
		 * Here is where the actual testing starts.
		 * 
		 * ************************************************
		 * \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
		 */
		
		// this tests the makeRLogin() and parseRLogin()
		System.out.println(user);
		String message = makeRLogin(user);
		System.out.println(message);
		User currentUser = parseRLogin(message);
		System.out.println(currentUser);
		
		// this tests the makeRLoadUser() and parseRLoadUser() methods
		System.out.println("\n\n\n****************\n LoadUser");
		System.out.println(user);
		message = makeRLoadUser(user);
		System.out.println(message);
		currentUser = parseRLoadUser(message);
		System.out.println(currentUser);
		
		// this tests the makeRSearchUser() and parseRSearchUser() methods
		System.out.println("\n\n****************\nSearchUser\n**************\n");
		List<User> userList = new ArrayList<User>();
		userList.add(user);
		userList.add(user2);
		
		for(int i = 0; i < userList.size(); i++){
			System.out.println(userList.get(i));
		}
		message = makeRSearchUser(userList);
		System.out.println(message);
		List<User> users = parseRSearchUser(message);
		for(int i = 0; i < userList.size(); i++){
			System.out.println(users.get(i));
		}
		
		// this tests the makeRSearchAppDate() and parseRSearchAppDate() methods
		System.out.println("\n\n***************\nSearch App Date\n***************\n");
		List<Appointment> appList = new ArrayList<Appointment>();
		appList.add(app);
		appList.add(app2);
		
		for(int i = 0; i < appList.size(); i++){
			System.out.println(appList.get(i));
		}
		message = makeRSearchAppDate(appList);
		System.out.println(message);
		List<Appointment> apps = parseRSearchAppDate(message);
		for(int i = 0; i < apps.size(); i++){
			System.out.println(apps.get(i));
		}
		
		// this tests the makeRSearchAppDate() and parseRSearchAppDate() methods
		System.out.println("\n\n**************\nSearch App SSN\n**************\n");
		for(int i = 0; i < appList.size(); i++){
			System.out.println(appList.get(i));
		}
		message = makeRSearchAppSSN(appList);
		System.out.println(message);
		apps = parseRSearchAppSSN(message);
		for(int i = 0; i < apps.size(); i++){
			System.out.println(apps.get(i));
		}
		
		// this prints all of the messages that are sent to the server.
		System.out.println(makeLogin("bob", "pass", 4));
		System.out.println(makeAddUser(user));
		System.out.println(makeLoadUser(4567));
		System.out.println(makeUpdateUser(user2.getSSN(), user2));
		System.out.println(makeDeleteUser(4567));
		System.out.println(makeSearchUser("BoB"));
		System.out.println(makeAddApp(app));
		System.out.println(makeUpdateApp(app));
		System.out.println(makeDeleteApp(456, new Date(345, 2, 4)));
		System.out.println(makeSearchAppDate(new Date(134, 4, 6)));
		System.out.println(makeSearchAppSSN(735));
		System.out.println(makeQuit());
	}
}